/*  This file is part of the comicconquer project
    Copyright (C) 2010 Reach <reach334@gmail.com>

    ComicConquer is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This software is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public 
    License along with this software.  If not, see <http://www.gnu.org/licenses/>.

*/

#ifndef PAGESTRUCT_H
#define PAGESTRUCT_H

#include "mist.h"
#include <QtGui/QtGui>
#include "highgui.h"
#include "cv.h"
#include "Configuration.h"

/**
 * Line for OpenCV.
 * 
 * @author reach (5/26/2010)
 */
struct Line
{
    CvPoint p1;
    CvPoint p2;

    Line(CvPoint& point1, CvPoint& point2)
    {
        p1 = point1;
        p2 = point2;
    }

    Line()
    {
    }
};
typedef QList<Line> LineList;
#define LINE_EXIST(line) ((line).p1.x != -1)

/**
 * Grid for scroll mode.
 * Just have top and bottom because left and right are the same of screen.
 * 
 * @author reach (5/26/2010)
 */
struct GridForScroll
{
    int top;
    int bottom;
};
typedef QVector<GridForScroll> GridForScrollVec;

enum PageContent 
{
    Cot_Origin,
    Cot_Scaled,
    Cot_Thresh,
    Cot_Contour,
    Cot_Line,
    Cot_Scroll,

    Cot_End
};

typedef QVector<QImage*> QImageVec;

/**
 * The struct to store informations for a divided page.
 * 
 * @author reach (5/26/2010)
 */
struct DivPage
{
    QMutex mutex;
    bool processed; // whether this page is processed
    int iPage;
    int iPageCount;
    int iDivPage;   // the current divPage
    int iDivPageCount;

    GridForScrollVec gridForScrolls;

    QImageVec images;

    DivPage()
    {
        processed = false;
        iPage = -1;

        images.resize(Cot_End);
        for (int i = 0; i < images.count(); i++)
        {
            images[i] = NULL;
        }
    }

    ~DivPage()
    {
        release();
    }

    void release()
    {
        QMutexLocker locker(&mutex);

        gridForScrolls.clear();

        for (int i = 0; i < images.count(); i++)
        {
            if (images[i] != NULL)
            {
                delete images[i];
                images[i] = NULL;
            }
        }

        processed = false;
    }

    bool isFirst()
    {
        return iPage == 0 && iDivPage == 0;
    }

    bool isLast()
    {
        return iPage == iPageCount - 1 && iDivPage == iDivPageCount - 1;
    }

};

/**
 * The struct to store informations for an original page.
 * 
 * @author reach (5/26/2010)
 */
struct Page
{
    QMutex mutex;
    bool loaded;    // whether this page is loaded
    bool needed;    // whether this page is needed to load
    bool processed;
    int iPage;
    int divCount;   // diveded images number, the MAX of which is 2
    int pageCount;

    DivPage* divPage[2];

    Page(){
        loaded = false;
        needed = false;
        processed = false;
        iPage = -1;
        divCount = 0;

        divPage[0] = new DivPage();
        divPage[1] = new DivPage();
    }

    ~Page(){
        delete divPage[0];
        delete divPage[1];
    }

    void release(){
        QMutexLocker locker(&mutex);

        divPage[0]->release();
        divPage[1]->release();

        loaded = false;
        needed = false;
    }

};

/**
 * The page queue where all page interfaces and current loaded page datas store.
 * 
 * @author reach (5/26/2010)
 */
class PageQueue
{
    //-- constructor and destructor
public:
    PageQueue();
    ~PageQueue();

    //-- public methods
public:
    int size();
    Page* getPage(int iPage);
    Page* getUnprocess(bool isPrev);
    void initPageList();
    void requestInit(int nPage);
    void moveTo(int iPage);
    void updateQueue();
    void requestReload();
    bool isReloadRequest();
    bool isInitRequest();
    void lock();
    void unlock();

    //-- private members
private:
    QMutex m_mutex;
    int m_quLen;
    int m_quLen_2;
    int m_nPage; // total page number
    int m_iProcessed; // number of processed pages
    int m_pageStart; // the page id of queue start. can be negative, adding m_quLen_2 when using
    int m_pageCur; // the current page
    int m_pageLast; // last page. it mean that queue need to be updated when the value don't equal to m_pageCur
    Page* m_pageList;

    bool m_reloadRequest; // whether need to reload
    bool m_initRequest;
};


#endif  // PAGESTRUCT_H
